package com.example.mychatroom.serviceImpl;

import com.example.mychatroom.a_utils.SessionKey;
import com.example.mychatroom.component.OnlineUserManager;
import com.example.mychatroom.mapper.MessageMapper;
import com.example.mychatroom.mapper.MessageSessionMapper;
import com.example.mychatroom.model.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.List;

/**
 * @className: WebSocketAPI
 * @author: 十三
 * @description:WebSocket接口
 * @date: 2025/2/28 22:36
 */
@Component
public class WebSocketAPI extends TextWebSocketHandler {

    @Autowired
    private OnlineUserManager onlineUserManager;

    @Autowired
    private MessageSessionMapper messageSessionMapper;

    @Autowired
    private MessageMapper messageMapper;

    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("WebSocket 链接成功");
        User user = (User) session.getAttributes().get(SessionKey.USERINFO_SESSION_KEY);
        if (user == null) {
            return;
        }
        //getAttributes()返回的是Map，通过get key的形式获取value
        String userAccount = user.getUserAccount();
        System.out.println("获取到的用户账号为：" + userAccount);
        onlineUserManager.online(userAccount,session);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        System.out.println("WebSocket 收到消息" + message.toString());
        //处理消息的接收、转发以及消息的保存记录
        //1、先获取当前用户的信息，后续进行消息转发啥的
        User user = (User) session.getAttributes().get(SessionKey.USERINFO_SESSION_KEY);
        if (user == null) {
            System.out.println("[WebSocketAPI] user == null! 用户未登录，无法进行消息转发~");
            return;
        }
        //2.针对请求进行解析
        String messageString = message.getPayload();
        //3.将JSON字符串转化成MessageRequest对象
        MessageRequest messageRequest = objectMapper.readValue(messageString,MessageRequest.class);
        if (messageRequest.getType().equals("message")) {
            //就进行消息转发
            transferMessage(user,messageRequest);
        }else {
            System.out.println("[WebSocketAPI] messageRequest.type 有误！" + message.getPayload());
        }
    }

    //此方法完成消息转发功能
    //第一个参数表示这个消息是从哪个用户发送过来的
    private void transferMessage(User fromUser, MessageRequest messageRequest) throws IOException {
        //1.先构造一个待转发的响应对象
        MessageResponse messageResponse = new MessageResponse();
        messageResponse.setType("message");
        messageResponse.setFromAccount(fromUser.getUserAccount());
        messageResponse.setFromName(fromUser.getUserName());
        messageResponse.setSessionId(messageRequest.getSessionId());
        messageResponse.setContent(messageRequest.getContent());
        String respJson = objectMapper.writeValueAsString(messageResponse);
        //2.需要根据请求中的sessionId，获取到这个MessageSession里都有哪些用户，通过查询数据库就能够获取到
        List<Friend> friendList= messageSessionMapper.getFriendBySessionId(messageRequest.getSessionId(),fromUser.getUserAccount());
        // 此处上述数据库查询会把当前发消息的用户剔除掉，最终转发的时候，则需要也把消息发送给发送消息的人
        Friend myself = new Friend();
        myself.setFriendAccount(fromUser.getUserAccount());
        myself.setFriendName(fromUser.getUserName());
        friendList.add(myself);
        //3.循环遍历上述的这个列表，给列表中的每个用户都发一份响应消息
        for (Friend friend: friendList) {
            //  知道了每个用户的userAccount，进一步的查询刚才准备好的OnlineUserManager，就知道了对应的WebSocketSession
            //  从而进行发送消息
            //  注意：除了给查询到的好友发消息，也要给自己也发一个，方便实现在自己的客户端上显示自己发送的消息
            //  注意：一个会话中，可能有多个用户（群聊），虽然客户端是没有支持群聊的（前端写起来比较麻烦），后端无论是API还是数据库上都是支持群聊的
            //      此处的转发功能逻辑也是支持群聊的
            WebSocketSession webSocketSession = onlineUserManager.getWebSocketSession(friend.getFriendAccount());
            if (webSocketSession == null){//用户不在线的情况，则默认不发送
                continue;
            }
            webSocketSession.sendMessage(new TextMessage(respJson));
        }
        //4.转发的消息，还需要存储到数据库，后续用户如果下线之后，重新上线，还可以通过历史消息的方式拿到之前的消息
        //  需要给message表当中写入消息记录
        Message message = new Message();
        message.setSessionId(messageRequest.getSessionId());
        message.setContent(messageRequest.getContent());
        message.setFromAccount(fromUser.getUserAccount());
        message.setFromName(fromUser.getUserName());
        messageMapper.add(message);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.out.println("WebSocket 出现异常" + exception.toString());
        User user = (User) session.getAttributes().get(SessionKey.USERINFO_SESSION_KEY);
        if (user == null) {
            return;
        }
        //getAttributes()返回的是Map，通过get key的形式获取value
        String userAccount = user.getUserAccount();
        System.out.println("获取到的用户账号为：" + userAccount);
        onlineUserManager.online(userAccount,session);
        onlineUserManager.logOut(userAccount,session);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        System.out.println("WebSocket 链接关闭" + status.toString());
        User user = (User) session.getAttributes().get(SessionKey.USERINFO_SESSION_KEY);
        if (user == null) {
            return;
        }
        //getAttributes()返回的是Map，通过get key的形式获取value
        String userAccount = user.getUserAccount();
        System.out.println("获取到的用户账号为：" + userAccount);
        onlineUserManager.online(userAccount,session);
        onlineUserManager.logOut(userAccount,session);
    }
}
